#include <iostream>
#include "Production.h"
#include "Graph.h"

extern TerminalSymbol dollar;



void test_first_and_follow(){
    vector<NonTerminalSymbol*> vct;
    NonTerminalSymbol Y("Y");
    NonTerminalSymbol T("T");
    NonTerminalSymbol E("E");
    NonTerminalSymbol X("X");
    TerminalSymbol times("*",LexemeCategory::NUMBERIC_OPERATOR);
    TerminalSymbol left_par("(",LexemeCategory::NUMBERIC_OPERATOR);
    TerminalSymbol right_par(")",LexemeCategory::NUMBERIC_OPERATOR);
    TerminalSymbol plus("+",LexemeCategory::NUMBERIC_OPERATOR);
    TerminalSymbol int_terminal("INT ",LexemeCategory::INTEGER_CONST);

    PRO_ID Y_one=Production::insert_production(&times,&T);// *T
    PRO_ID T_one=Production::insert_production(&left_par,&E,&right_par);// (E)
    PRO_ID T_two=Production::insert_production(&int_terminal,&Y);// int Y
    PRO_ID X_one=Production::insert_production(&plus,&E); //+E
    PRO_ID E_one=Production::insert_production(&T,&X); //TX
    Y.add_production(Y_one);    //Y-> *T
    Y.add_production(Production::get_epsilo_production_id()); // Y->ε
    T.add_production(T_one);    //T-> (E)
    T.add_production(T_two);    //T-> int Y
    X.add_production(X_one);    //X-> +E
    X.add_production(Production::get_epsilo_production_id()); // X->ε
    E.add_production(E_one);    //E-> TX
    vct.push_back(&Y);
    vct.push_back(&T);
    vct.push_back(&E);
    vct.push_back(&X);
    //新加入的语法
    NonTerminalSymbol S("S"); //S-> E
    PRO_ID S_one=Production::insert_production(&E);
    S.add_production(S_one);
    vct.push_back(&S);
    for(auto elem:vct){
        elem->get_info();
    }

    for(auto elem:vct){
        elem->calcu_first();
    }

    S.follow_set.insert(&dollar);

    for(auto elem:vct){
        elem->calcu_follow_pre();
    }
    for(auto elem:vct){
        elem->calcu_follow();
    }


    DFA dfa(&S);
    dfa.startup_item_set.get()->get_info();
    dfa.get_info();
}


void test_dfa(){
    vector<NonTerminalSymbol*> vct;
    NonTerminalSymbol E("E");
    NonTerminalSymbol T("T");
    TerminalSymbol int_terminal("INT ");
    TerminalSymbol times_terminal("*");
    TerminalSymbol plus_terminal("+");
    TerminalSymbol left_pa("(");
    TerminalSymbol right_pa(")");

    PRO_ID E_one=Production::insert_production(&T,&plus_terminal,&E);//T+E
    PRO_ID E_two=Production::insert_production(&T);//T
    PRO_ID T_one=Production::insert_production(&int_terminal,&times_terminal,&T);//int * T
    PRO_ID T_two=Production::insert_production(&int_terminal);//int
    PRO_ID T_three=Production::insert_production(&left_pa,&E,&right_pa);//(E)

    E.add_production(E_one);
    E.add_production(E_two);
    T.add_production(T_one);
    T.add_production(T_two);
    T.add_production(T_three);

    vct.push_back(&E);
    vct.push_back(&T);

    //新加入的语法
    NonTerminalSymbol S("S"); //S-> E
    PRO_ID S_one=Production::insert_production(&E);
    S.add_production(S_one);
    vct.push_back(&S);
    for(auto elem:vct){
        elem->get_info();
    }

    for(auto elem:vct){
        elem->calcu_first();
    }

    S.follow_set.insert(&dollar);

    for(auto elem:vct){
        elem->calcu_follow_pre();
    }
    for(auto elem:vct){
        elem->calcu_follow();
    }


    DFA dfa(&S);
    //dfa.startup_item_set.get()->get_info();
    dfa.get_info();

}

void test_left_recursion(){
    NonTerminalSymbol S("S");
    TerminalSymbol A("a");
    TerminalSymbol B("b");
    
    PRO_ID S_one=Production::insert_production(&S,&A); 
    PRO_ID S_two=Production::insert_production(&B);

    S.add_production(S_one); //S--> Sa
    S.add_production(S_two); //S--> b

    S.get_info();

    S.calcu_first();
}


void test_action(){
    vector<NonTerminalSymbol*> vct;
    NonTerminalSymbol E("E");
    NonTerminalSymbol T("T");
    NonTerminalSymbol F("F");
    TerminalSymbol int_terminal("id ");
    TerminalSymbol times_terminal("*");
    TerminalSymbol plus_terminal("+");
    TerminalSymbol left_pa("(");
    TerminalSymbol right_pa(")");
    //新加入的语法


    PRO_ID E_one=Production::insert_production(&E,&plus_terminal,&T);//E+T
    PRO_ID E_two=Production::insert_production(&T);//T
    PRO_ID T_one=Production::insert_production(&T,&times_terminal,&F);//T * F
    PRO_ID T_two=Production::insert_production(&F);//F
    PRO_ID F_one=Production::insert_production(&left_pa,&E,&right_pa);//(E)
    PRO_ID F_two=Production::insert_production(&int_terminal);//id
    
    NonTerminalSymbol S("S"); //S-> E
    PRO_ID S_one=Production::insert_production(&E);
    S.add_production(S_one);
    E.add_production(E_one);
    E.add_production(E_two);
    T.add_production(T_one);
    T.add_production(T_two);
    F.add_production(F_one);
    F.add_production(F_two);

    vct.push_back(&E);
    vct.push_back(&T);
    vct.push_back(&F);
    vct.push_back(&S);
    for(auto elem:vct){
        elem->get_info();
    }

    for(auto elem:vct){
        elem->calcu_first();
    }

    S.follow_set.insert(&dollar);

    for(auto elem:vct){
        elem->calcu_follow_pre();
    }
    for(auto elem:vct){
        elem->calcu_follow();
    }


    DFA dfa(&S);
    //dfa.startup_item_set.get()->get_info();
    dfa.get_info();
    vector<TerminalSymbol*> terminal_vct{&int_terminal,&plus_terminal,&times_terminal,&left_pa,&right_pa,&dollar};
    vector<NonTerminalSymbol*> nonterminal_vct{&E,&T,&F};
    dfa.calcu_action(terminal_vct);
    dfa.calcu_goto(nonterminal_vct);
}

int main(){
    test_action();

    return 0;
}

